﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Index.Bintree;
using NetTopologySuite.Index.Chain;

namespace NetTopologySuite.Algorithm
{
	public class MCPointInRing : IPointInRing
	{
		public MCPointInRing(ILinearRing ring)
		{
			this._ring = ring;
			this.BuildIndex();
		}

		private void BuildIndex()
		{
			this._tree = new Bintree<MonotoneChain>();
			foreach (MonotoneChain monotoneChain in MonotoneChainBuilder.GetChains(CoordinateArrays.RemoveRepeatedPoints(this._ring.Coordinates)))
			{
				Envelope envelope = monotoneChain.Envelope;
				this._interval.Min = envelope.MinY;
				this._interval.Max = envelope.MaxY;
				this._tree.Insert(this._interval, monotoneChain);
			}
		}

		public bool IsInside(Coordinate pt)
		{
			this._crossings = 0;
			Envelope rayEnv = new Envelope(double.NegativeInfinity, double.PositiveInfinity, pt.Y, pt.Y);
			this._interval.Min = pt.Y;
			this._interval.Max = pt.Y;
			IEnumerable<MonotoneChain> enumerable = this._tree.Query(this._interval);
			MCPointInRing.MCSelecter mcSelecter = new MCPointInRing.MCSelecter(this, pt);
			foreach (MonotoneChain mc in enumerable)
			{
				MCPointInRing.TestMonotoneChain(rayEnv, mcSelecter, mc);
			}
			return this._crossings % 2 == 1;
		}

		private static void TestMonotoneChain(Envelope rayEnv, MCPointInRing.MCSelecter mcSelecter, MonotoneChain mc)
		{
			mc.Select(rayEnv, mcSelecter);
		}

		private void TestLineSegment(Coordinate p, LineSegment seg)
		{
			Coordinate p2 = seg.P0;
			Coordinate p3 = seg.P1;
			double x = p2.X - p.X;
			double num = p2.Y - p.Y;
			double x2 = p3.X - p.X;
			double num2 = p3.Y - p.Y;
			if ((num > 0.0 && num2 <= 0.0) || (num2 > 0.0 && num <= 0.0))
			{
				double num3 = (double)RobustDeterminant.SignOfDet2x2(x, num, x2, num2) / (num2 - num);
				if (0.0 < num3)
				{
					this._crossings++;
				}
			}
		}

		private readonly ILinearRing _ring;

		private Bintree<MonotoneChain> _tree;

		private int _crossings;

		private readonly Interval _interval = new Interval();

		private class MCSelecter : MonotoneChainSelectAction
		{
			public MCSelecter(MCPointInRing container, Coordinate p)
			{
				this._container = container;
				this._p = p;
			}

			public override void Select(LineSegment ls)
			{
				this._container.TestLineSegment(this._p, ls);
			}

			private readonly MCPointInRing _container;

			private readonly Coordinate _p;
		}
	}
}
